
package models.aaa;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.TypedQuery;

import models.Store;
import play.db.jpa.JPA;

/**
 * A web Resource. The URL field points to the descriptor (metadata) of the
 * resource. The about field points to the resource itself.
 * 
 * @author laurent@opprecht.info
 */
@Entity
// @Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "about_id" }),
// @UniqueConstraint(columnNames = { "url_id" }) })
public class Resource extends Node {

    public static class Finder {

        public TypedQuery<Resource> createQuery(final String sql) {
            TypedQuery<Resource> result = JPA.em().createQuery(sql, Resource.class);
            return result;
        }

        public TypedQuery<Resource> query(final String sql, final Object... parameters) {
            TypedQuery<Resource> result = createQuery(sql);
            for (int i = 0; i < parameters.length; i++) {
                result.setParameter(i + 1, parameters[i]);
            }
            return result;
        }

        public TypedQuery<Resource> query(final String sql) {
            return query(sql, new Object[] {});
        }

        public Resource byId(final Long id) {
            return JPA.em().find(Resource.class, id);
        }

        public Resource byUrl(final Url url) {
            if (url == null) {
                return null;
            }
            if (url.getId() == null) {
                return null;
            }

            String sql = "SELECT e FROM Resource e WHERE e.url = ?";
            List<Resource> items = query(sql, url).getResultList();
            for (Resource item : items) {
                return item;
            }
            return null;
        }

        public Resource byUrl(final String url) {
            Url u = Url.find.byUrl(url);
            return byUrl(u);
        }

    }

    public static final Finder find             = new Finder();

    @SuppressWarnings("unused")
    private static final long  serialVersionUID = 8744068302677756989L;

    public static Resource get(final String url) {
        return get(Url.get(url));
    }

    public static Resource get(final Url url) {
        if (url == null) {
            return null;
        }
        Resource result = find.byUrl(url); //
        if (result != null) {        	
            return result;
        }
        result = new Resource(url);
        Store.save(result);
        return result;
    }

    // public static boolean has(final Url url) {
    // get will never work as it always return a values
    // return get(url) != null;
    // }

    @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    private Url     url     = null;

    @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    private Url     about   = null;

    @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH, CascadeType.MERGE }, fetch = FetchType.LAZY, optional = true)
    private Asset   asset   = null;

    private boolean isValid = false;

    protected Resource() {
    }

    protected Resource(final Url url) {
        this();
        setUrl(url);
    }

    /**
     * @return the data
     */
    public Url getUrl() {
        return url;
    }

    /**
     * @param data
     */
    public void setUrl(final Url value) {
        this.url = value;
    }

    /**
     * @return the about
     */
    public Url getAbout() {
        return about;
    }

    /**
     * @param about
     */
    public void setAbout(final Url about) {
        this.about = about;
    }

    /**
     * @param about
     */
    public void setAbout(final String about) {
        this.about = Url.get(about);
    }

    public boolean isValid() {
        return isValid;
    }

    public void setValid(final boolean value) {
        isValid = value;

        if (asset == null) {
            return;
        }

        boolean assetIsValid = false;
        for (Resource resource : asset.getResources()) {
            if (resource.isValid()) {
                assetIsValid = true;
                break;
            }
        }
        asset.setValid(assetIsValid);
    }

    public Asset getAsset() {
        return asset;
    }

    public void setAsset(final Asset value) {
        this.asset = value;
    }

}
